using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

using KLATencor.CommonApp.Infrastructure.StateMachine;

using Syncfusion.Windows.Forms.Diagram;
using Syncfusion.Windows.Forms.Diagram.Controls;

using StateMachine_Graphical_Editor.Error;
using StateMachine_Graphical_Editor.Shapes;
using StateMachine_Graphical_Editor.Utils;
using StateMachine_Graphical_Editor.Utils.Forms_RunTime_Managment;
using StateMachine_Graphical_Editor.Graphics_Rendering;

// added for Runtime
using KLATencor.CommonApp.EPSM;
using KLATencor.Infrastructure.Component;
using KLATencor.CommonApp.StateMachine.Facade;

using System.Runtime.Serialization;

namespace StateMachine_Graphical_Editor.Forms
{
    /// <summary>
    /// Display first level states present in a selected state machine object
    /// </summary>
    [Serializable]
    public partial class MainForm : StatesForm
    {
        #region Members:

        //static members in use of the GrphicsFactory
        /// <summary>
        /// The full path file name retrieved from user
        /// </summary>
        public static string fileName;

        /// <summary>
        /// The graphical symbols needed to display in the form
        /// </summary>
        public static PaletteGroupView symbols;

        /// <summary>
        /// Indicates all statesFroms if simulator is enabled 
        /// </summary>
        public static bool simulatorEnabled = false;

        /// <summary>
        /// File name of the selected states integrated library DLL file 
        /// </summary>
        private string stateslibrary;

        /// <summary>
        /// File name of the selected transitions integrated library DLL file
        /// </summary>
        private string transitionsLibrary;

        //interfaces to get running State Machines
        private IKTStateMachine epsm = null;
        private IKTStateMachine ktcms = null;

        #region Constants:

        private const string ENABLE_EVENT_SIMULATOR = "Enable Event Simulator";
        private const string DISABLE_EVENT_SIMULATOR = "Disable Event Simulator";
        private const string STATES_LIBRARY_TITLE = "Load Integrated States Library";
        private const string TRANSITIONS_LIBRARY_TITLE = "Load Integrated Transitions Library";

        private const string APP_LOGGER_NAME = "StateMachine Graphical Editor";

        //for loading the template
        private const string RESOURCE_FOLDER = "/Resources";
        private const string TEMPLATE_FILENAME = "MachineTemplate.xml";
        private const string TEMPLATE_FULL_PATH = "C:/Documents and Settings/Administrator/My Documents/Visual Studio 2005/Projects/state machine graphical editor/state machine graphical editor/Resources/MachineTemplate.xml";

        #endregion

        #endregion

        #region C'tor:

        public MainForm(SelectionMode selectionMode)
        {
            InitializeComponent();
            switch (selectionMode)
            {
                case SelectionMode.EDITOR:
                    initiateDesinerMainForm();
                    break;
                case SelectionMode.RUN_TIME:
                    initiateRunTimeMainForm();
                    break;
            }
        }

        /// <summary>
        /// Initiate the MainForm for run time enviroment
        /// </summary>
        public void initiateRunTimeMainForm()
        {
            //InitializeComponent();
            symbols = this.paletteGroupViewStateMachine;
            diagramElements = new NodeCollection();

            //initialize forms manager
            FormsManager.getManager().initializeManager(this);

            machineLoadingGroupBox.Visible = false;
            RunTimegroupBox.Visible = true;
            enableEventSimulatorToolStripMenuItem.Enabled = false;
            ConnectButton.Enabled = false;

            if (this.ktcms == null && this.epsm == null)
            {
                ComponentSystem CS = ComponentSystemFactory.GetComponentSystem(KLATencor.CommonApp.BusinessLogic.Utilities.CommonApplicationNameConstants.CommonApplicationName);
                this.ktcms = (IKTStateMachine)CS.ComponentManager.CreateComponent(KLATencor.CommonApp.BusinessLogic.Utilities.CommonApplicationNameConstants.CarrierManagementServices);
                this.epsm = (IKTStateMachine)CS.ComponentManager.CreateComponent(KLATencor.CommonApp.BusinessLogic.Utilities.CommonApplicationNameConstants.EquipmentProcessingStateModel);
            }

            ExistingMachinesBox.Items.Clear();
            ExistingMachinesBox.Items.AddRange(this.epsm.GetStateMachineNames());
            ExistingMachinesBox.Items.AddRange(this.ktcms.GetStateMachineNames());
            ExistingMachinesBox.DropDownStyle = ComboBoxStyle.DropDownList;

            this.paletteGroupBar1.Visible = false;

        }

        /// <summary>
        /// Initiate the MainForm for a design enviroment
        /// </summary>
        public void initiateDesinerMainForm()
        {
            //InitializeComponent();
            symbols = this.paletteGroupViewStateMachine;
            diagramElements = new NodeCollection();
            
            //initialize forms manager
            FormsManager.getManager().initializeManager(this);
        }

        #endregion

        #region Event Handlers for controls in the form

        private void MainForm_Load(object sender, EventArgs e)
        {
            //TODO - an opened feature request by KLA to Suncfusion:
            //       to have a layout manager that will be able to present 
            //       circles on the board (i.e: 1->2->3->1)
            this.diagram.LayoutManager = new HierarchicLayoutManager(model, 0, 40, 80);

            loadNewMachine();
        }
       
        #region Disgn Time related events:

        private void BrowseButton_Click(object sender, EventArgs e)
        {
            if (BrowseButton.Enabled == false)
                return;
            openXmlFileDialog.ShowDialog();
        }

        private void openXmlFileDialog_FileOk(object sender, CancelEventArgs e)
        {
            load_files_box.Text = openXmlFileDialog.FileName;
            load_button.Enabled = true;
        }

        private void selectStatesButton_Click(object sender, EventArgs e)
        {
            openIntegratedLibrariesDialog.Title = STATES_LIBRARY_TITLE;
            openIntegratedLibrariesDialog.ShowDialog();
        }

        private void selectTransitionsButton_Click(object sender, EventArgs e)
        {
            openIntegratedLibrariesDialog.Title = TRANSITIONS_LIBRARY_TITLE;
            openIntegratedLibrariesDialog.ShowDialog();
        }

        private void openIntegratedLibrariesDialog_FileOk(object sender, CancelEventArgs e)
        {
            String fullPathFileName = openIntegratedLibrariesDialog.FileName;
            FileInfo fileInfo = new FileInfo(fullPathFileName);

            if (openIntegratedLibrariesDialog.Title.Equals(STATES_LIBRARY_TITLE))
                statesTextBox.Text = fileInfo.Name;
            if (openIntegratedLibrariesDialog.Title.Equals(TRANSITIONS_LIBRARY_TITLE))
                transitionsTextBox.Text = fileInfo.Name;
        }

        private void load_button_Click(object sender, EventArgs e)
        {
            try
            {
                fileName = load_files_box.Text;
                stateslibrary = statesTextBox.Text;
                transitionsLibrary = transitionsTextBox.Text;

                loadAndDisplayMachine(fileName, stateslibrary, transitionsLibrary);
                if (machine != null)
                    System.Windows.Forms.MessageBox.Show(
                    this,
                    "Machine was successfully loaded to Editor",
                    "State Machine is loaded",
                    MessageBoxButtons.OK);

            }
            catch (EditorMachineException exception)
            {
                MessageBox.Show(exception.StackTrace, "Error occured while loading machine");
            }
        }

        private void load_files_box_TextChanged(object sender, EventArgs e)
        {
            if (load_files_box.Text.Equals(""))
            {
                load_button.Enabled = false;
                ClearTextBox.Enabled = false;
            }
            else
            {
                load_button.Enabled = true;
                ClearTextBox.Enabled = true;
            }
        }

        private void ClearTextBox_Click(object sender, EventArgs e)
        {
            clearBoard();
        }

        #endregion

        #region Simulator related events:

        private void startMachine_Click(object sender, EventArgs e)
        {
            if (this.machine == null)
            {
                MessageBox.Show(
                    "There is no loaded machine available",
                    "Machine not loaded",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                return;
            }

            try
            {
                this.machine = initializer.getRoot() as StateMachine;

                //register machine events
                //this.machine.OnStateChange += new StateMachine.StateChange(onTransitionOccured);

                this.paletteGroupBar1.Visible = false;

                if (eventDropDownBox.Items.Count > 0)
                    this.addEvent.Enabled = true;

                this.displayMode = DisplayModes.VIEW_MODE;
                //this.CleanBoard.Enabled = false;
                //this.DisplayButton.Enabled = false;
                this.startMachine.Enabled = false;
                this.stopMachineButton.Enabled = true;

                this.machine.Start();

                //MessageBox.Show("Machine started");
            }
            catch (Exception SMException)
            {
                this.paletteGroupBar1.Visible = true;
                //this.CleanBoard.Enabled = true;
                //this.DisplayButton.Enabled = true;
                this.startMachine.Enabled = true;
                this.stopMachineButton.Enabled = false;
                this.displayMode = DisplayModes.EDIT_MODE;
                MessageBox.Show(SMException.Message);
            }
        }

        private void stopMachineButton_Click(object sender, EventArgs e)
        {
            this.machine.Shutdown();
            this.displayMode = DisplayModes.EDIT_MODE;
            this.startMachine.Enabled = true;
            this.stopMachineButton.Enabled = false;
            this.addEvent.Enabled = false;

            FormsManager.getManager().resetManager();

            //this.CleanBoard.Enabled = true;
            //this.DisplayButton.Enabled = true;
            //search for the current state and unmark it:
            this.clearCurrent();
            this.paletteGroupBar1.Visible = true;
        }

        #endregion

        #region Run Time related events:

        private void ConnectButton_Click(object sender, EventArgs e)
        {
            try
            {
                ConnectButton.Enabled = false;
                ExistingMachinesBox.Enabled = false;
                //initialize machine interfaces:

                this.machine = this.epsm.GetStateMachine(ExistingMachinesBox.Text);
                if (this.machine == null)
                    this.machine = this.ktcms.GetStateMachine(ExistingMachinesBox.Text);
                if (this.machine == null)
                {
                    MessageBox.Show("Error", "Error occured while loading machine");
                    return;
                }

                //intialize data structure for out-going transitions
                InGoingTransitionDS.getDS().initializeDS(machine);

                this.initializer = GraphicsFactory.getFactory().createInitializer(this.machine, this);

                //reset LayoutManager, event simulator, and model:
                this.eventDropDownBox.Items.Clear();
                this.eventsQueue.Items.Clear();
                diagramElements.Clear();
                startMachine.Enabled = false;
                model.Clear();

                //present the list of all possible events
                updateEventsList();

                DisplayMachine();
                searchInitialCurrents();

                this.machine.OnStateChange += new StateMachine.StateChange(onTransitionOccured);

                DisconnectButton.Enabled = true;
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.StackTrace, "Error occured while connecting machine");
            }
        }

        private void ExistingMachinesBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (ExistingMachinesBox.Items != null)
                ConnectButton.Enabled = true;
        }

        private void DisconnectButton_Click(object sender, EventArgs e)
        {
            //close all windows and unregister events
            FormsManager.getManager().resetManager();

            //clear memory and bord
            this.clearCurrent();
            diagramElements.Clear();
            model.Clear();

            // Enable / disable all relevant buttons
            DisconnectButton.Enabled = false;
            ConnectButton.Enabled = true;
            ExistingMachinesBox.Enabled = true;
        }

        #endregion

        #endregion

        #region Main Menu related events:

        #region File Menu:

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            loadNewMachine();
        }

        private void openXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openXmlFileDialog.ShowDialog();
        }

        private void openStatesDllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openIntegratedLibrariesDialog.Title = STATES_LIBRARY_TITLE;
            openIntegratedLibrariesDialog.ShowDialog();
        }

        private void openTransionDllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openIntegratedLibrariesDialog.Title = TRANSITIONS_LIBRARY_TITLE;
            openIntegratedLibrariesDialog.ShowDialog();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dirty = false;
            MessageBox.Show("Item is not implemented yet");
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Item is not implemented yet");
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region Edit Menu:

        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.diagram.Model.HistoryManager.Undo();
        }

        private void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.diagram.Model.HistoryManager.Redo();
        }

        #endregion

        #region Tool Menu:

        private void enableEventSimulatorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            simulatorEnabled = !simulatorEnabled;
            // event simulator
            eventsGroupBox.Visible = !eventsGroupBox.Visible;
            // start/stop machine
            activationPanel.Visible = !activationPanel.Visible;
            // text in menu
            enableEventSimulatorToolStripMenuItem.Text = 
                switchSimulatorText(enableEventSimulatorToolStripMenuItem.Text);
        }

        #endregion

        #endregion

        #region Helper Methods:

        /// <summary>
        /// Create the state machine object out of the given resources
        /// </summary>
        /// <param name="file">the XML file name with full path</param>
        /// <param name="integratedStatesLib">Integrated state library DLL file (name only)</param>
        /// <param name="integratedTransLib">Integrated transition library DLL file (name only)</param>
        /// <exception cref="StateMachine_Graphical_Editor.Error.EditorMachineException"></exception>
        private void loadStateMachine(String file, String integratedStatesLib, String integratedTransLib)
        {
            try
            {
                machine = null;
                machine = new StateMachine(
                    file,
                    new IStateMachineHostImpl(),
                    integratedStatesLib,
                    integratedTransLib,
                    APP_LOGGER_NAME);

                //register form to machine events
                machine.OnStateChange += new StateMachine.StateChange(onTransitionOccured);

                long MaxStateId = 0;
                long MaxTransionId = 0;
                foreach (State st in machine.AllStates)
                {
                    MaxStateId = Math.Max(st.ID, MaxStateId);
                }
                foreach (Transition tr in machine.Transitions)
                {
                    MaxTransionId = Math.Max(tr.TransitionNumber, MaxTransionId);
                }

                //create graphics initializer
                initializer = GraphicsFactory.getFactory().createInitializer(machine, this);

                //intialize data structure for in-going transitions
                InGoingTransitionDS.getDS().initializeDS(machine);

                //reset LayoutManager, event simulator, and model
                this.eventDropDownBox.Items.Clear();
                this.eventsQueue.Items.Clear();
                diagramElements.Clear();
                startMachine.Enabled = false;
                model.Clear();

                //get available events 
                updateEventsList();
            }
            catch (Exception e)
            {
                throw new EditorMachineException("Cannot load machine", e);
            }
        }

        /// <summary>
        /// Load the machine selected
        /// </summary>
        private void loadNewMachine()
        {
            //get the template file
            DirectoryInfo applicationDir =
                new DirectoryInfo(
                    Directory.GetParent(Application.ExecutablePath) + RESOURCE_FOLDER);

            String file = applicationDir.GetFiles(TEMPLATE_FILENAME)[0].FullName;

            loadAndDisplayMachine(file, "", "");
        }

        /// <summary>
        /// loads a specified machine and displays the first states level
        /// </summary>
        /// <param name="fileName">XML file representing the StateMachine</param>
        /// <param name="stateslibrary">DLL file for integrated states library</param>
        /// <param name="transitionsLibrary">DLL file for integrated transitions library</param>
        private void loadAndDisplayMachine(string fileName,
            string stateslibrary, string transitionsLibrary)
        {
            try
            {
                clearBoard();
                loadStateMachine(fileName, stateslibrary, transitionsLibrary);
                DisplayMachine();              
            }
            catch (EditorMachineException exception)
            {
                MessageBox.Show(exception.Message, "Error loading state machine");
            }
        }

        /// <summary>
        /// Displays the machine loaded.
        /// </summary>
        private void DisplayMachine()
        {
            if (initializer != null)
            {
                diagramElements.AddRange(initializer.getGraphicalStateList());

                int index = 0;
                model.AppendChildren(diagramElements, out index);

                //set a layout manager
                if (this.diagram.LayoutManager == null)
                    this.diagram.LayoutManager = new HierarchicLayoutManager(model, 0, 40, 80); //- happens in OnLoad event
                
                this.diagram.LayoutManager.UpdateLayout(null);
                this.diagram.UpdateView();

                this.startMachine.Enabled = true;
            }

            this.diagram.Controller.SelectionList.Clear();
        }

        /// <summary>
        /// Searches for the current state and last transition.
        /// <para>Used while connecting to a running machine</para>
        /// </summary>
        private void searchInitialCurrents()
        {
            //search for current state in the connected machine
            foreach (Node tmp in diagramElements)
            {
                GState tmpState = tmp as GState;
                if (tmpState != null && tmpState.LogicState.Equals(machine.State))
                {
                    tmpState.CurrentState = true;
                    break;
                }
            }

            //search for current transition in the connected machine
            foreach (Node tmp in diagramElements)
            {
                GTransition tmpTrans = tmp as GTransition;
                if (tmpTrans != null && tmpTrans.LogicTransition != null && tmpTrans.LogicTransition.Equals(machine.LastTransition))
                {
                    tmpTrans.LastTransition = true;
                    break;
                }
            }

            //one of the nodes wasn't found in MainForm
            if (CurrentGState == null || LastTransition == null)
            {
                SubStatesForm newForm = new SubStatesForm(machine.State.Parent, machine.State, DisplayModes.VIEW_MODE);
                FormsManager.getManager().addAndShow(machine.LastTransition, newForm);
            }

        }

        /// <summary>
        /// Return the text to display on simulator menu tool strip
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private string switchSimulatorText(string text)
        {
            if (ENABLE_EVENT_SIMULATOR.Equals(text))
                return DISABLE_EVENT_SIMULATOR;
            else if (DISABLE_EVENT_SIMULATOR.Equals(text))
                return ENABLE_EVENT_SIMULATOR;
            else return "";
        }

        /// <summary>
        /// cleans the application from the elements
        /// </summary>
        private void clearBoard()
        {
            diagramElements.Clear();
            startMachine.Enabled = false;
            model.Clear();

            load_files_box.Text = "";
            statesTextBox.Text = "";
            transitionsTextBox.Text = "";

            load_button.Enabled = false;
        }

        #endregion

        #region StatesForm abstract Method Implementation:

        public override string getName()
        {
            return "Root";
        }

        public override State getState()
        {
            return null;
        }

        public override void permitEventLaunching(bool isPermitted)
        {
            eventDropDownBox.SelectedItem = null;
            addEvent.Enabled = isPermitted;
        }

        #endregion

        #region Serializable Implementation:

        public MainForm(SerializationInfo info, StreamingContext str)
            : base(info, str)
        {
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext str)
        {
        }

        private void clearCurrent()
        {
            if (this.LastTransition != null)
                this.LastTransition.LastTransition = false;
            if (this.CurrentGState != null)
                this.CurrentGState.CurrentState = false;
        }

        #endregion

    }
}